package jfprincesstests.agents;

import java.util.*;

import jfuzzyprincepless.agents.*;
import jfuzzyprincepless.zarchive.algorithm.structure.ifcnstr.*;
import jfuzzyprincepless.zarchive.algorithm.structure.ICommandConstruction;
import jfuzzyprincepless.zarchive.agents.BaseUtilityFuncAgent;
import jfuzzyprincepless.zarchive.agents.IUtilityFuncNegotiationAgent;
import jfuzzyprincepless.zarchive.negotiation.protocols.propositionnetwork.DefaultExecIfProtocol;
import jfuzzyprincepless.negotiation.DefaultNegotiationContext;
import jfuzzyprincepless.negotiation.IExecutionContext;
import jfuzzyprincepless.negotiation.INegotiation;
import jfuzzyprincepless.negotiation.INegotiationContext;
import jfuzzyprincepless.negotiation.impl.UnmodifiableNegotiationContext;
import jfuzzyprincepless.negotiation.services.IService;
import laboratoryQ.junit.ignore.patch.BaseTestCase;
import jfprincesstests.fakes.FakeCondition;

public class TestAgents
	extends BaseTestCase
{
	public void testBaseAgent() {
		INegotiatingAgent baseAgent = new BaseNegotiationAgent() {};
		final List<IService> registstred = new ArrayList<IService>();

		INegotiationContext context = new INegotiationContext() {
			@Override
			public void registerService(IService service) {
				registstred.add(service);
			}
			@Override
			public <ServT extends IService> ServT getService(
				Class<ServT> clazz
			) {
				throw new UnsupportedOperationException("not implemented");
			}
			@Override
			public <ServT extends IService> void registerService(
				Class<ServT> clazz,
				ServT service
			) {
				registstred.add(service);
			}
		};

		baseAgent.onNegotiationStart(context);
		boolean isAlive = baseAgent.negotiate(context);
		assertFalse(isAlive);
		assertEquals(1, registstred.size());
		assertSame(registstred.get(0), baseAgent);
	}

	private static interface IGetIntServ extends IService {
		public int getInt();
	}

	private static class GetIntServ implements IGetIntServ {
		public int val;
		public GetIntServ() {
			this(0);
		}
		public GetIntServ(int val) {
			this.val = val;
		}
		@Override
		public int getInt() {
			return val;
		}
	}

	public void testRegisterServicesAgent() {
		GetIntServ getIntServ = new GetIntServ();
		RegisterServicesAgent servRegistrer =
			new RegisterServicesAgent(
				getIntServ
			);

		final List<Integer> values =
			new ArrayList<Integer>();

		NegotiationIfConstruction ifConstr =
			new NegotiationIfConstruction(
				new FakeCondition(0.0) {
					@Override
					public boolean negotiate(
						INegotiationContext context
					) {
						IGetIntServ getInt =
							context.getService(
								IGetIntServ.class
							);
						int val = getInt.getInt();
						values.add(val);
						return false;
					}
				},
				Collections.<ICommandConstruction>emptyList(),
				Collections.<ICommandConstruction>emptyList()
			);
		ifConstr.extractAgentsFromConstructions();

		ifConstr.getAgents().add(servRegistrer);

		INegotiation negotiation =
			new DefaultExecIfProtocol().createNegotiation(ifConstr, null);

		getIntServ.val = 123;
		negotiation.negotiate();
		getIntServ.val = 456;
		negotiation.negotiate();
		getIntServ.val = 789;
		negotiation.negotiate();

		assertEquals(Arrays.asList(123, 456, 789), values);
	}

	private static class TestBaseUtilityFuncAgent
		extends BaseUtilityFuncAgent
	{
		@Override
		public double computeUtility(
			INegotiationContext context
		) {
			return 123;
		}
	}

	public void testBaseUtilityFuncAgent() {
		TestBaseUtilityFuncAgent agent =
			new TestBaseUtilityFuncAgent();
		assertIsInstance(
			agent,
			IUtilityFuncNegotiationAgent.class
		);
		IUtilityFuncNegotiationAgent iagent = agent;
		assertFalse(iagent.negotiate(null));
		iagent.onSingleNegotiationStageEnd(null);

		boolean caught = false;
		try {
			iagent.onNegotiationStart(null);
			assertFalse(true);
		} catch (NullPointerException e) {
			caught = true;
		}
		assertTrue(caught);
	}

	public void testUnmodifiableNegotiationContext() {
		INegotiationContext innerContext =
			new DefaultNegotiationContext();
		UnmodifiableNegotiationContext context =
			new UnmodifiableNegotiationContext(innerContext);
		INegotiationContext icontext = context;
		assertNotNull(icontext);
		assertNull(context.getService(IGetIntServ.class));

		innerContext.registerService(new GetIntServ(123));
		assertNotNull(context.getService(IGetIntServ.class));
		assertEquals(
			123,
			context.getService(IGetIntServ.class).getInt()
		);

		try {
			context.registerService(new GetIntServ(456));
			assertFalse(true);
		} catch (UnsupportedOperationException e) { }
		assertEquals(
			123,
			context.getService(IGetIntServ.class).getInt()
		);
		assertEquals(
			123,
			context.getService(IGetIntServ.class).getInt()
		);

		try {
			INegotiationContext emptyContext =
				(INegotiationContext)IExecutionContext.EMPTY;
			emptyContext.registerService(new GetIntServ(456));
			assertFalse(true);
		} catch (UnsupportedOperationException e) { }
	}
}
